﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EditoneLib.Streams.Audio
{
    public class FadeStream : ReadonlyStream
    {
        public enum FadeDirection
        {
            In,
            Out
        }

        private readonly Stream _sourceStream;
        private readonly FadeDirection _direction;

        public FadeStream(Stream sourceStream, FadeDirection direction)
        {
            _sourceStream = sourceStream;
            _direction = direction;
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            var floatCount = count/sizeof (float);
            var byteCount = floatCount*sizeof (float);
            
            byte[] sourceBuffer = new byte[byteCount];

            var chunkSignificance = (float)floatCount / Length;
            var chunkCoef = (float)Position / Length;

            byteCount = _sourceStream.Read(sourceBuffer, 0, byteCount);
            floatCount = byteCount / sizeof(float);

            float[] floatBuffer = new float[floatCount];
            Buffer.BlockCopy(sourceBuffer, 0, floatBuffer, 0, byteCount);

            for (var i = 0; i < floatCount; i++)
            {
                var sampleCoef = (float)i / floatCount * chunkSignificance + chunkCoef;

                switch (_direction)
                {
                    case FadeDirection.In:
                        sampleCoef = sampleCoef;
                        break;
                    case FadeDirection.Out:
                        sampleCoef = 1.0f - sampleCoef;
                        break;
                    default:
                        sampleCoef = 1.0f;
                        break;
                }

                floatBuffer[i] = floatBuffer[i] * sampleCoef;
            }
            
            Buffer.BlockCopy(floatBuffer,0,buffer,offset,byteCount);
            return byteCount;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _sourceStream.Seek(offset, origin);
        }

        public override long Length
        {
            get { return _sourceStream.Length; }
        }

        public override long Position
        {
            get { return _sourceStream.Position; }
            set { _sourceStream.Position = value; }
        }
    }
}
